package com.cw.java8.方法引用;

import com.cw.java8.functionInterface.Person;

import java.util.function.BinaryOperator;

/**
 * 类型	语法	对应的Lambda表达式
 * 静态方法引用	类名::staticMethod	(args) -> 类名.staticMethod(args)
 * 实例方法引用	inst::instMethod	(args) -> inst.instMethod(args)
 * 对象方法引用	类名::instMethod	(inst,args) -> inst 的类名.instMethod(args)
 * 构建方法引用	类名::new	(args) -> new 类名(args)
 */
public class Main {

    public static void main(String[] args) {
    //1.静态方法引用
        // 函数式接口，其需要重写的方法为： T apply(T t, T u);
        BinaryOperator<Integer> binaryOperator = (a, b) -> (a >= b) ? a : b;
        // 这两个是等价的
        binaryOperator = Math::max;
        //这里其实引用的是 Math 类下的静态方法
//        public static int max(int a, int b) {
//            return (a >= b) ? a : b;
//        }
//        我们发现我们要实现的比较的方法在 Math 类中已经有现成的逻辑内容结构了，所以我们直接引用过来使用。
//        这里的 Math::max 等价于 (a, b) -> (a >= b) ? a : b

    //2.实例方法引用
        Comparable comparable = o -> {
            if (null == o) {
                return 0;
            } else {
                return 1;
            }
        };
        instMethod testInstanceFun = new instMethod();
        comparable = testInstanceFun::isNull;
        Object obj= new Object();
        System.out.println(comparable.compareTo(obj));
//        这里想要实现对比的 Comparable 的逻辑为 当对象为 null 时，返回0，其他就返回1，
//        这个和静态方法引用类似，使用 TestInstanceFun 对象的实例去引用即可。

    //3.对象方法引用
//        特殊条件：
//        1.至少要有一个入参，而且方法体中必须只调用该入参的方法而不做其他操作
//        2.第二个参数开始，为调用的方法的入参列表。

        //具体调用
        // 假设具体的逻辑为 将字符串进行首尾切割。
        instMethod2 testInterface = (originalString, a, b) -> originalString.substring(a, b);
        // 这里可以转换使用 String 的对象方法引用
        testInterface = String::substring; //引用的 String 的 substring(int beginIndex, int endIndex) 方法
//        第一个入参的 originalString 调用其 substring 方法，后面的两个参数 a 和 b，
//        作为 substring 的入参，因此可以转换成 String::substring ，相当于 originalString.substring(a, b) 来使用。


//  4.构造方法引用
//   构造器引用与方法引用很类似，只不过方法名为 new。被引用的类必须存在一个构造方法与函数式接口的抽象方法参数列表一致，以及回参为该类的实例。
        TestStructureFun testStructureFun = (a, b) -> new Person(a, b);
        // 可以转为这种写法
        testStructureFun = Person::new;
//   这里的 Person::new 是 Person 构造器的一个引用。根据上下文推测出，这里引用的是 Person 中两个参数的构造器。
    }

    /**
     *  4.总结：
     *  方法引用不能独立存在，总是会转换为函数式接口的实例。
     *  如果有多个同名的重载方法， 编译器就会尝试从上下文中找出你指的那一个方法。
     *  例如该文章中的 静态方法引用 示例中：
     *  Math.max 方法有四个版本，有用于整数的， 有用于 double 值。选择哪一个版本取决于 Math::max 转换为哪个函数式接口的方法参数。
     *  示例里 Math::max 检测到当前调用的方法的两个入参都为 Integer 类型，就转换为对应的方法参数 --> public static int max(int a, int b)
     */
}

